/*********************************************************
 * 初学之家(http://www.g2room.com)，提供Java、Javascript（js）、Jquery、
 * 等一些工具或常用功能的实现例子代码，希望能给初学者提供学习和工作上的帮助，
 * 也希望有想提供源代码的朋友能联系我，一起努力，提供更多、更全面、更详细的
 * 一些初学代码例子及经验，帮助更多的人。
 * 
 * 我的联系方式：E-Mail：g2room@163.com
 * 网址：http://www.g2room.com
 * QQ：天涯（1173930590）
 * QQ交流群：323642758
 * 
 * 本站内容为提供各种java、javascript(JS)常用的工具源代码、实例（示例）、
 * 基本配置、教程、手册等；目前Java代码提供的工具（或转换）例子代码如下：
 * BASE64转换工具、bytes相关操作、email收发、文件操作（读写、拷贝、遍历、
 * 多线程copy等）、json格式转换、日志（Log4j）操作工具、Lucene搜索引擎的
 * 创建索引和搜索、各种不同Map的使用、定时器（Quartz）的使用例子、Socket的
 * 连接传输数据例子、WebService的例子及一些常用的工具类如String、Date及
 * JDK自带的一些工具类及函数的使用例子。
 * 
 * 说明：如需直接使用本站的例子代码，请保留此说明
 * 
 ********************************************************/
package com.g2room.quartz.engine;

import java.util.Date;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.DateBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

import com.g2room.quartz.engine.jobs.PrintJobImpl;

/**
 * Quartz核心引擎类
 *
 * @createTime: Jun 21, 2013 5:00:50 PM
 * @author: <a href="mailto:g2room@163.com">天涯</a>
 * @version: 0.1
 * @lastVersion: 0.1
 * @updateTime: 
 * @updateAuthor: <a href="mailto:g2room@163.com">天涯</a>
 * @changesSum: 
 * 
 */
public class QuartzEngine {

	/** Quartz任务调度工厂 */
	private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
	
	/**
	 * 获取Quartz任务已经实例化了的调度工厂类
	 *
	 * @return {SchedulerFactory} 已经实例化后的调度工厂类
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Jun 21, 2013 5:01:27 PM
	 */
	public static SchedulerFactory getSchedulerFactory(){
		return schedulerFactory;
	}
	
	/**
	 * 使用quartz实现的调度任务
	 *
	 * @throws SchedulerException
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Jun 21, 2013 5:07:28 PM
	 */
	public static void jobSChedule() throws SchedulerException {
		System.out.println("进入任务调度！");
		// 从工厂里面拿到一个scheduler实例
		Scheduler scheduler = schedulerFactory.getScheduler();
		cronJob(scheduler);
		// 开始调度
		scheduler.start();
	}
	

	/**
	 * 简单调度实例，同一个Job可以注册到多个scheduler
	 *
	 * @param {Scheduler} scheduler Quartz的调度
	 * @throws SchedulerException
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Jun 21, 2013 5:11:52 PM
	 */
	public static void simpleJob(Scheduler scheduler) throws SchedulerException {
		System.out.println("简单调度作业开始！");
		// 计算任务的开始时间
		// DateBuilder.evenMinuteDate(Date date)方法是取指定时间的整数分钟
		// 		比如指定的时间为13:23:10，则会在13:24时执行
		// DateBuilder.evenMinuteDateAfterNow()方法是取当前时间后的整数分钟
		// 		比如启动的时候时间为13:23:10，则会在13:24时执行
		// DateBuilder.evenMinuteDateBefore(Date date)方法是取指定时间前的整数分钟
		// 		比如指定的时间为13:23:10，则会在13:23时执行
		// 同样的还有：
		// 按小时执行：evenHourDate(Date date)、evenHourDateAfterNow()、evenHourDateBefore(Date date)
		// 按秒执行：evenSecondDate(Date date)、evenSecondDateAfterNow()、evenSecondDateBefore(Date date)
		Date runTime = DateBuilder.evenMinuteDate(new Date());
		// nextGivenSecondDate方法表示：启动后在指定秒数倒计时后运行
		// nextGivenMinuteDate(Date date, int secondBase)方法表示：启动后在指定分数倒计时后运行
//		Date runTime = DateBuilder.nextGivenSecondDate(null, 16);
		// 真正执行的任务并不是Job接口的实例，而是用反射的方式实例化的一个Jobs实例
		JobDetail job = JobBuilder.newJob(PrintJobImpl.class).withIdentity("simpleJob",
				"simpleGroup").build();
		// 定义一个触发器，startAt方法定义了任务应当开始的时间
		Trigger trigger = TriggerBuilder.newTrigger().withIdentity("simpleTrigger",
				"simpleTriggerGroup").startAt(runTime).build();
		// 任务和Trigger放入scheduler，进行执行
		scheduler.scheduleJob(job, trigger);
		// 下面再使用同一个job定义了执行任务，可使用不同的任务再次定义
		JobDetail job1 = JobBuilder.newJob(PrintJobImpl.class).withIdentity("simpleJob1",
		"simpleGroup").build();
		// 定义一个触发器，startAt方法定义了任务应当开始的时间
		Trigger trigger1 = TriggerBuilder.newTrigger().withIdentity("simpleTrigger1",
		"simpleTriggerGroup").startAt(runTime).build();
		scheduler.scheduleJob(job1, trigger1);
		System.out.println("简单调度作业完成！");
	}
	
	/**
	 * 重复指定次数且带参数传递的Job
	 *
	 * @param {Scheduler} scheduler Quartz的调度
	 * @throws SchedulerException
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Jun 21, 2013 5:57:18 PM
	 */
	public static void paramentJob(Scheduler scheduler) throws SchedulerException {
		System.out.println("带参数的调度作业开始！");
		// 重复执行,表示第一次执行完之后，每隔3秒钟执行一次，重复5次，
		// withRepeatCount参数不包括第一次执行那次，即job3总共执行6次
		// SimpleScheduleBuilder：	重复执行，需要在Trigger的设置里面加入，
		// 							设置重复次数和重复时间即可。
		// repeatForever()方法永远表示一直重复执行，相应的可以设置按小时、分钟、秒一直执行。
		// 本示例设置为withIntervalInSeconds(2)，表示每2秒执行一次。
		// 对应的每指定毫秒、分钟、小时为：withIntervalInMilliseconds、withIntervalInMinutes、withIntervalInHours
		JobDetail job = JobBuilder.newJob(PrintJobImpl.class).withIdentity("paramentJob", "paramentGroup").build();
		// 此处使用的为无状态Job，则map里面的值如果被Job改变后，不会保留。
		// 如要保留，则需要使用有状态的Job-->StatefulJob，例子如下注释的代码：
		// JobDetail job = JobBuilder.newJob(StatJobImpl.class).withIdentity("job3", "testGroup").build();
		job.getJobDataMap().put(IJob.JOB_DATA_MAP_NAMW, "job3");
		job.getJobDataMap().put(IJob.JOB_DATA_MAP_NUM, 1);
		Trigger trigger = TriggerBuilder.newTrigger()
				.withIdentity("paramentTriggerJob", "paramentTriggerGroup2").withSchedule(
						SimpleScheduleBuilder.simpleSchedule().withRepeatCount(5)
						.withIntervalInSeconds(2))
				.build();
		scheduler.scheduleJob(job, trigger);
		System.out.println("简单调度作业完成！");
	}
	
	public static void cronJob(Scheduler scheduler) throws SchedulerException {
		JobDetail job = JobBuilder.newJob(PrintJobImpl.class).withIdentity("cronJob", "cronJobGroup").build();
		/**
		使用Trigger的子类CronTrigger；
		withSchedule中的参数变为CronScheduleBuilder
	    CronScheduleBuilder可以通过类似"0/10 * * * * ?"这种表达式来创建定时任务  
	    当前这个表达式的定义是每个秒是10的倍数，或者是0的时候，都触发任务
		*/
	  	CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(
				"cronTrigger", "cronTriggerGroup").withSchedule(
				CronScheduleBuilder.cronSchedule("49 * * * * ?")).build();
	  	/**
	  	--------------------------------------
	  	   秒 分 时  日 月 周 年
	  	   0 0  12  *  * ?         每天12点触发
	  	   0 15 10  ?  * *         每天10点15分触发
	  	   0 15 10  *  * ?         每天10点15分触发
	  	   0 15 10  *  * ? *       每天10点15分触发
	  	   0 15 10  *  * ? 2005      2005年每天10点15分触发
	  	   0 *  14  *  * ?            每天下午的 2点到2点59分每分触发
	  	   0 0/5 14 *  * ?          每天下午的 2点到2点59分(整点开始，每隔5分触发)
	  	   0 0/5 14,18 * * ?       每天下午的 2点到2点59分(整点开始，每隔5分触发) 每天下午的 18点到18点59分(整点开始，每隔5分触发)
	  	   0 0-5 14 *  * ?          每天下午的 2点到2点05分每分触发
	  	   0 10,44 14 ? 3 WED      3月分每周三下午的 2点10分和2点44分触发
	  	   0 15 10 ? * MON-FRI     从周一到周五每天上午的10点15分触发
	  	   0 15 10 15 * ?          每月15号上午10点15分触发
	  	   0 15 10 L * ?           每月最后一天的10点15分触发
	  	   0 15 10 ? * 6L          每月最后一周的星期五的10点15分触发
	  	   0 15 10 ? * 6L 2002-2005    从2002年到2005年每月最后一周的星期五的10点15分触发
	  	   0 15 10 ? * 6#3         每月的第三周的星期五开始触发
	  	   0 0 12 1/5 * ?          每月的第一个中午开始每隔5天触发一次
	  	   0 11 11 11 11 ?         每年的11月11号 11点11分触发(光棍节)
	  	--------------------------------------
	  	其次，通配符，主要的有星号(*)；问号(?)；减号(-)；逗号(,)；斜杠(/)；L字母；W字母；井号(#). 
		星号：表示任意时刻
		问号：只能在日或周字段上使用，http://blog.csdn.net/chh_jiang/article/details/4603529 这里有比较清晰的解释，简单的理解就是日期和星期是有冲突的，指定其中一个的话，另外一个是没办法指定的，比如每个月12号和每个星期二，这两个是"互斥"的，不能用日期和周来指定所有“每个是星期二的12号”这个时间。
		减号：范围，如 1-5秒
		逗号：列表，如 1,5,10 秒
		斜杠：等步长序列，如3/13秒 表示 3,16,29,42,55,3,16...
		L：仅在日和周上支持，表示允许的最后一个值，注意不要让范围和列表与L连用
		W：工作日
		#号：为给定月份指定具体的工作日实例。把“MON#2”放在周内日期字段中，表示把任务安排在当月的第二个星期一。
		#号和L W用的比较少，其实简单实用的话，根据那些注释中的去改就够了~~
	  	*/
	  	scheduler.scheduleJob(job, cronTrigger);
		// 开始调度
		scheduler.start();
	}
	
	public static void main(String[] args) {
//		QuartzEngine qe = new QuartzEngine();
		try {
			QuartzEngine.jobSChedule();
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
